package Work;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;

import moodish.comm.ClientComm;
import moodish.comm.ClientSideMessage;
import moodish.comm.ServerSideMessage;


/***
 * 
 * @author Paulo Coelho
 * 
 * This class is the brige, interaction, between the client and the server by sockets.
 *
 */
public class ClientSide implements ClientComm, Runnable, Serializable {
	public static final int PORT = 8082;

	private Socket s;
	private ObjectOutputStream out;
	private ObjectInputStream in;
	private LinkedList<ClientMessage> inMsgClientList = new LinkedList<ClientMessage>();
	private String nickName;

	/***
	 * 
	 * Thread which is waiting for objects.
	 * When they come, it will save them all into a list.
	 * 
	 */
	public void run() {
		ToSerialize inComing = null;

		try {
			while (isConnected()) {
				inComing = (ToSerialize) in.readObject();
				addTolist(inComing);
			}
			in.close();

			s.close();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
/***
 * This method adds to the list a serialized message;
 */
	public void addTolist(ToSerialize inComing) {
		ClientMessage cm;
		cm = (ClientMessage) inComing.getObject();
		synchronized (inMsgClientList) {
			inMsgClientList.add(cm);
			inMsgClientList.notify();
		}

	}

	@Override
	public void connect(String host, String nickname)
			throws UnknownHostException, IOException {
		this.nickName = nickname;
		this.s = new Socket(host, PORT);
		out = new ObjectOutputStream(s.getOutputStream());
		in = new ObjectInputStream(s.getInputStream());
		Thread thisThread = new Thread(this);
		thisThread.start();
		ServerMessage msg = new ServerMessage(
				ServerSideMessage.Type.CLIENT_CONNECTED, nickName, "");
		send(msg);
	}

	@Override
	public boolean isConnected() {
		if (s.isConnected()) {
			return true;
		}
		return false;
	}

	@Override
	public void disconnect() {
		try {
			ServerMessage msg = new ServerMessage(
					ServerSideMessage.Type.CLIENT_DISCONNECTED, nickName, "");
			send(msg);
			shutDown();
		} catch (Exception e) {
		}
	}

	@Override
	public ClientSideMessage getNextMessage() {
		ClientMessage msg;
		synchronized (inMsgClientList) {

			while (hasNextMessage() == false) {
				try {
					inMsgClientList.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			msg = (ClientMessage) inMsgClientList.poll();
		}
		return msg;
	}

	@Override
	public boolean hasNextMessage() {
		if (!inMsgClientList.isEmpty()) {
			return true;
		}
		return false;
	}

	@Override
	public void sendMoodishMessage(String moodishMessage) {
		ServerMessage msg = new ServerMessage(
				ServerSideMessage.Type.MOODISH_MESSAGE, nickName,
				moodishMessage);
		send(msg);
	}

	@Override
	public void friendship(String nickname) {
		ServerMessage msg = new ServerMessage(
				ServerSideMessage.Type.FRIENDSHIP, nickName, nickname);

		send(msg);
	}

	@Override
	public void unfriendship(String nickname) {
		ServerMessage msg = new ServerMessage(
				ServerSideMessage.Type.UNFREINDSHIP, nickName, nickname);
		send(msg);
	}
/***
 * This method sends a serialized message from the type server trough the output channel;
 */
	public void send(ServerMessage msg) {
		ToSerialize msgSerialized = new ToSerialize(msg);

		try {
			out.writeObject(msgSerialized);
			out.reset();

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void shutDown() {
		try {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			s.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
